﻿// Nail framework
//
// Copyright © Frank Nagl, 2009
// admin@franknagl.de
// www.franknagl.de
//
namespace Nail
{
    using System.Drawing;
    using System.Drawing.Imaging;
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// Segments a colored image.
    /// </summary>
    public class Posterization
    {
        //byte exponent = 6; // 2^6 = 64
        ///// <summary>
        ///// Gets or sets the exponent of the Threshold (== 2^exponent). 
        ///// Default value: 6. Cannot be bigger than 8.
        ///// </summary>
        ///// <remarks>Default value: 6</remarks>
        ///// <value>The exponent of the Threshold.</value>
        //public byte Exponent
        //{
        //    get { return exponent; }
        //    set 
        //    {
        //        if (value > 8)
        //            throw new ArgumentException("Exponent cannot be bigger than 8.");
                
        //        exponent = value; 
        //        threshold = (byte)(Math.Pow(2, value) - 1); 
        //    }
        //}

        byte threshold = 90;//64;
        /// <summary>
        /// Gets or sets the threshold for the segmentation. Value must be 2^<paramref name="Exponent"/>.
        /// </summary>
        /// <remarks>Default value: 64</remarks>
        /// <value>The threshold value.</value>
        public byte Threshold
        {
            get { return threshold; }
            set { threshold = value; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Posterization"/> class.
        /// </summary>
        public Posterization() { }

        /// <summary>
        /// Extracts the color segments of the original bitmap as pixel-connected regions.
        /// </summary>
        public void ProcessImage(Bitmap image)
        {
            // check image format
            if (image.PixelFormat != PixelFormat.Format24bppRgb)
                throw new ArgumentException("Source image can be color (24 bpp) image only");
            
            int w = image.Width;
            int h = image.Height;            
            Rectangle rect = new Rectangle(0, 0, w, h);

            // lock source bitmap data
            BitmapData imageData = image.LockBits(
                rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int offset = imageData.Stride - w * 3;

            // process image
            unsafe
            {
                byte* src = (byte*)imageData.Scan0.ToPointer();
                // for each line
                for (int y = 0; y < h; y++)
                {
                    // for each pixel in line
                    for (int x = 0; x < w; x++, src += 3)
                    {
                        src[RGB.R] = (byte)((src[RGB.R] / threshold) * threshold);
                        src[RGB.G] = (byte)((src[RGB.G] / threshold) * threshold);
                        src[RGB.B] = (byte)((src[RGB.B] / threshold) * threshold);
                        //src[RGB.R] = (byte)(src[RGB.R] ^ threshold);//Bit moving trial
                        //src[RGB.G] = (byte)(src[RGB.G] ^ threshold); //... but to unflexible
                        //src[RGB.B] = (byte)(src[RGB.B] ^ threshold);
                    }
                    src += offset;
                }
            }
            // unlock destination image
            image.UnlockBits(imageData);
        }
    }
}
